﻿Imports System
Imports System.Collections
Imports System.IO
Imports System.Xml
Imports System.Xml.Serialization
Imports System.Xml.XPath
Imports ICSharpCode.SharpZipLib.Zip
Imports unRar

Public Class readingList
    Implements IDisposable
    '****************************************************************
    '   Class readinglist                                           *
    '   Copyright 2008 Stephen Wrighton                             *
    '   Purpose:    Reading List of archives.                       *
    '****************************************************************
    '   History                                                     *
    '   09/30/2008      CREATED         SSW                         *
    '****************************************************************

    Private _readingList As List(Of String)
    Private _curFile As String
    Private _curIndex As Integer = 0
    Private disposedValue As Boolean = False        ' To detect redundant calls
    Private path As String
    Private TempFolder As String


#Region "Property"
    Public Property CurrentFile() As String
        Get
            Return _curFile
        End Get
        Set(ByVal value As String)
            _curFile = value
            If _readingList.Contains(value) Then
                Dim f As New HelpFind(value)
                _curIndex = _readingList.FindIndex(AddressOf f.Find)
            Else
                _readingList.Add(value)
                _curIndex = _readingList.Count - 1
            End If
        End Set
    End Property

    Public ReadOnly Property FileList() As List(Of String)
        Get
            If _readingList Is Nothing Then _readingList = New List(Of String)
            Return _readingList
        End Get
    End Property
#End Region

#Region "Constructors"
    Public Sub New()
        _readingList = New List(Of String)
        _curFile = String.Empty
    End Sub

    Public Sub New(ByVal lst As List(Of String))
        _readingList = lst
        _curFile = String.Empty
    End Sub
    Public Sub New(ByVal array As Array)
        _readingList = New List(Of String)
        For Each s As String In array
            _readingList.Add(s)
            _curFile = String.Empty
        Next
    End Sub

    Public Sub New(ByVal currentFile As String, ByVal unused As Boolean)
        Me.New(currentFile, IO.Directory.GetFiles(IO.Path.GetDirectoryName(currentFile)))

    End Sub

    Public Sub New(ByVal currentFile As String, ByVal lst As List(Of String))
        _readingList = lst
        Me.CurrentFile = currentFile
    End Sub
    Public Sub New(ByVal currentFile As String, ByVal array As Array)
        _readingList = New List(Of String)
        For Each s As String In array
            _readingList.Add(s)
        Next
        Me.CurrentFile = currentFile
    End Sub

    ''' <summary>
    ''' This builds a Reading List object from a Reading List FILE 
    ''' </summary>
    ''' <param name="filePath"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal filePath As String)
        If Not IO.File.Exists(filePath) Then Throw New FileNotFoundException()
        Me._curIndex = -1
        Me.path = filePath
        Dim str As String = My.Computer.FileSystem.SpecialDirectories.CurrentUserApplicationData
        Dim fileName As String = IO.Path.GetFileNameWithoutExtension(Me.path)
        Dim ext As String = IO.Path.GetExtension(Me.path)
        TempFolder = str & "\readlists\" & fileName
        _readingList = New List(Of String)
        ext = Replace(ext, ".", "")
        Select Case ext
            Case "gnz", "gzip", "zip"
                unZip()
                LoadFileNames()
            Case "gnr", "rar"
                unRar()
                LoadFileNames()
            Case Else
                Throw New NotImplementedException(String.Format("Using {0} has not been implemented yet.", ext))
        End Select
    End Sub
#End Region

    Private Sub unZip()
        If Not IO.Directory.Exists(TempFolder) Then IO.Directory.CreateDirectory(TempFolder)
        Dim s As New ZipInputStream(File.OpenRead(path))

        Dim theEntry As ZipEntry = s.GetNextEntry
        While Not theEntry Is Nothing
            Dim fileName As String = IO.Path.GetFileName(theEntry.Name)

            If Not fileName Is String.Empty AndAlso Not IO.File.Exists(TempFolder & "/" & fileName) Then
                Dim streamWriter As FileStream
                streamWriter = File.Create(TempFolder & "/" & fileName)
                Dim size As Integer = 2048
                Dim abyData(2048) As Byte
                While True
                    size = s.Read(abyData, 0, abyData.Length)
                    If size > 0 Then
                        streamWriter.Write(abyData, 0, size)
                    Else ' size > 0 
                        Exit While
                    End If ' size > 0 
                End While
                streamWriter.Flush()
                streamWriter.Close()
                streamWriter.Dispose()
            End If

            theEntry = s.GetNextEntry
        End While ' Not theEntry Is Nothing 	
    End Sub

    Private Sub unRar()
        If Not IO.Directory.Exists(TempFolder) Then IO.Directory.CreateDirectory(TempFolder)
        Dim d As New Decompressor(Me.path)
        Dim b As Boolean = d.UnPackAll(Me.TempFolder)
        If Not b Then
            Throw New Exception("Rar Failed To Decompress")
        End If
    End Sub

    Private Sub LoadFileNames()
        Dim di As New IO.DirectoryInfo(Me.TempFolder)
        Dim aryFi As IO.FileInfo() = di.GetFiles("*.xml")
        Dim x As Boolean = True
        If aryFi.GetLength(0) > 0 Then x = Not LoadFilesFromReadingList(aryFi(0).FullName)

        If x Then
            Dim fileList As New List(Of String)
            LoadFilesFromSubFolders(Me.TempFolder, fileList)
            fileList.Sort()
            For Each s As String In fileList
                Me._readingList.Add(s)
            Next
        End If
    End Sub

    Private Sub LoadFilesFromSubFolders(ByVal dirPath As String, ByRef fileList As List(Of String))
        For Each fn As String In Directory.GetFiles(dirPath)
            Dim ext As String = Replace(IO.Path.GetExtension(fn), ".", "")
            Select Case LCase(Trim(ext))
                Case "xml"
                    ' Ignore 
                Case Else
                    fileList.Add(fn)
            End Select
        Next

        For Each dn As String In Directory.GetDirectories(dirPath)
            LoadFilesFromSubFolders(dn, fileList)
        Next ' Each dn As String In Directory.GetDirectories(dirPath) 
    End Sub ' LoadFilesFromSubFolders 


    Private Function LoadFilesFromReadingList(ByVal manifestFile As String) As Boolean
        LoadFilesFromReadingList = False
        Try
            Dim archs = XDocument.Load(manifestFile)
            Dim x = From arch In archs...<chapter> _
                    Order By arch.@sequence Ascending _
                    Select arch.@fileName
            For Each item In x
                Me._readingList.Add(Me.TempFolder & "\" & item)
            Next
            LoadFilesFromReadingList = True
        Catch ex As Exception
        End Try

    End Function


#Region "destructors"
    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                _readingList = Nothing
                _curFile = Nothing
                _curIndex = Nothing
            End If

            ' TODO: free shared unmanaged resources
        End If
        Me.disposedValue = True
    End Sub

#Region " IDisposable Support "
    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region
#End Region

    Public Function getFileByIndex(ByVal index As Integer) As String
        If index >= 0 AndAlso index < Me._readingList.Count Then
            Me._curFile = _readingList(index)
            Me._curIndex = index
        Else
            Throw New ArgumentException("The selected Index is out of bounds")
        End If
        Return Me._curFile
    End Function

    Public Function GetNextFile() As String
        _curIndex += 1
        If _curIndex >= Me._readingList.Count Then _curIndex = Me._readingList.Count - 1
        _curFile = Me._readingList(_curIndex)
        Return _curFile
    End Function

    Public Function GetPreviousFile() As String
        _curIndex -= 1
        If _curIndex <= 0 Then _curIndex = 0
        _curFile = Me._readingList(_curIndex)
        Return _curFile
    End Function

    Private Class HelpFind
        Public _str As String
        Public Sub New(ByVal aVal)
            _str = aVal
        End Sub
        Public Function Find(ByVal aVal As String) As Boolean
            Return _str.Equals(aVal)
        End Function
    End Class

    Public Function HasPrevious() As Boolean
        If _curIndex > 0 Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Function HasNext() As Boolean
        If _curIndex < Me._readingList.Count Then
            Return True
        Else
            Return False
        End If
    End Function

    Public Function Save() As Boolean
        Me.Save(Me.path)
    End Function

    Public Function Save(ByVal fileName As String) As Boolean
        ' TODO Build Save Process 
    End Function

End Class
